/**
 * 线程池封装, 能停止线程池, 支持各类形式的回调函数, 需要C++11支持
 * 
 * 开发者   : Marco
 * 创建时间 : 2016年5月26日, 上午11:20
 */

#if (defined(__cplusplus) && __cplusplus >= 201103L)

#ifndef __MARCOPP_MT_TPOOL_HPP__
#define __MARCOPP_MT_TPOOL_HPP__

#include <vector>
#include <queue>
#include <thread>
#include <mutex>
#include <condition_variable>

namespace marco {
namespace mt { // multi thread

/**
 * 线程池封装类
 */
class threadpool {
public:
    /**
     * 构造
     * @param threads
     */
    threadpool(size_t threads) : stop(false) {
	for (size_t i = 0; i < threads; ++i)
	    workers.emplace_back(
		[this] {
		    for (;;) {
			std::function<void() > task;

			{
			    std::unique_lock<std::mutex> lock(this->queue_mutex);
			    this->condition.wait(lock, [this] {
				return this->stop || !this->tasks.empty(); }); // 如果设置了停止或者空队列则wait继续等待
			    if (this->stop && this->tasks.empty()) // 设置了停止并且所有任务处理完成, 表示被外部停止, 则退出线程
				return;
			    task = std::move(this->tasks.front()); // 函数对象
			    this->tasks.pop(); // 出队列
			}

			task(); // 执行函数
		    }
		}
	    );
    }

    /**
     * 添加一个任务到队列,工作线程会依次执行
     * @param __f 任务执行函数
     * @param __args 参数列表,如果是类成员函数,则第一次参数必须是该类的对象地址,由于是异步调用,注意指针引用类参数的生命周期
     */
    template<typename _Callable, typename... _Args> void add_task(_Callable&& __f, _Args&&... __args) {
	auto task = std::bind(std::forward<_Callable>(__f), std::forward<_Args>(__args)...);
	{
	    std::unique_lock<std::mutex> lock(queue_mutex);
	    if (stop)
		throw std::runtime_error("enqueue on stopped ThreadPool");
	    tasks.emplace(task);
	}
	condition.notify_one();
    }

    /**
     * 析构, 设置停止标志, 并通知所有工作线程, 等待线程退出.
     */
    ~threadpool() {
	{
	    std::unique_lock<std::mutex> lock(queue_mutex);
	    stop = true;
	}

	condition.notify_all();

	for (std::thread &worker : workers)
	    worker.join();
    }
    
private:
    explicit threadpool(const threadpool& ths) = delete;
    explicit threadpool(threadpool && ths) = delete;
    threadpool& operator= (const threadpool& ths) = delete;
    threadpool& operator= (const threadpool&& ths) = delete;
    
    std::vector<std::thread> workers;		// 线程对象
    std::queue<std::function<void()> > tasks;	// 任务队列
    
    std::mutex queue_mutex;
    std::condition_variable condition;
    bool stop;
};

} // namespace mt
} /* namespace marco */
#endif /* __MARCOPP_MT_TPOOL_HPP__ */
#endif /* __cplusplus */

